
#include "Map.h"
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include "MapView.h"
#include "Application.h"

//
// Constructor
//

Map::Map(MapView *_parent)
{
	parent = _parent;
	Clear();
	Initialize();
}

Map::Map(int _width, int _height)
{
	SetTerrainSize(_width, _height);
	Initialize();
}

//
// Initialize
//

void Map::Initialize()
{
	// Setup the bgQuad
	InitQuad(tile);
	SetQuadTexCo(tile);
}

//
// SetSize
//

void Map::SetTerrainSize(int width, int height)
{
	tWidth = width;
	tHeight = height;
	terrain.resize(tWidth*tHeight);
}

//
// Clear
//

void Map::Clear()
{
	SetTerrainSize(1, 1);
}

//
// Resize
//

void Map::Resize(int width, int height)
{
	vector<int> newTerrain(width * height, -1);

	int w = (width < tWidth) ? width : tWidth;
	int h = (height < tHeight) ? height : tHeight;

	for(int i = 0; i < h; i++)
	for(int j = 0; j < w; j++)
		newTerrain[i*width+j] = terrain[i*tWidth+j];

	terrain = newTerrain;

	tWidth = width;
	tHeight = height;
}

//
// Load
//

bool GetString(fstream &file, char *str)
{
	int i = 0;
	while(file.good())
	{
		file.get(str[i]);
		if(str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
		{
			str[i] = 0;
			return true;
		}
		i++;
	}
	if(i == 0)
		return false;
	str[i] = 0;
	return true;
}

bool GetInt(fstream &file, int &val)
{
	char str[16];
	if(!GetString(file, str))
		return false;
	val = atoi(str);
	return true;
}

bool Map::LoadTerrain(const char *filePath)
{
	fstream file; 
	file.open(filePath, ios_base::in);
	if(!file.is_open()) return false;

	char setFilePath[256];
	if(!GetString(file, setFilePath))
	{
		file.close();
		return false;
	}

	tileSet = GetTileSet(setFilePath);
	TileSet &set = GetTileSet(tileSet);
	tile.tex = set.tex;

	int width, height;
	if(!GetInt(file, width) || !GetInt(file, height))
	{
		file.close();
		return false;
	}

	SetTerrainSize(width, height);

	for(int i = 0; i < height; i++)
	for(int j = 0; j < width; j++)
	{
		if(!GetInt(file, Cell(i, j)))
		{
			file.close();
			SetTerrainSize(1, 1);
			return false;
		}
	}

	terrainArea.Set(0, 0, width*set.imageSize, height*set.imageSize);
	parent->InitializeViewArea();

	file.close();
	return true;
}

bool Map::LoadScenario(const char *filePath)
{
	return false;
}

//
// Save
//

bool Map::SaveTerrain(const char *filePath)
{
	fstream file; 
	file.open(filePath, ios_base::out);
	if(!file.is_open()) return false;

	TileSet &set = GetTileSet(tileSet);

	file << set.filePath << " " << tWidth << " " << tHeight << " ";

	for(int i = 0; i < tHeight; i++)
	{
		for(int j = 0; j < tWidth; j++)
			file << GetTerrain(i, j) << " ";
	}

	file.close();
	return true;
}

bool Map::SaveScenario(const char *filePath)
{
	return false;
}

//
// SetTerrainPoint
//

void Map::SetTerrainPoint(hgeRect &viewArea, float x, float y, int t)
{
	int x0, y0;
	CalculatePoint(viewArea, x, y, x0, y0);
	if(x0 < 0 || x0 >= tWidth || y0 < 0 || y0 >= tHeight)
		return;
	terrain[y0*tWidth + x0] = t;
}

//
// CalculatePoint
//

void Map::CalculatePoint(hgeRect &viewArea, float x, float y, int &x0, int &y0)
{
	TileSet &set = GetTileSet(tileSet);

	const float scale = ScreenWidth() / (viewArea.x2 - viewArea.x1);
	const float imageSize = set.imageSize * scale;

	x0 = int((x + viewArea.x1*scale - 0.5f*imageSize) / imageSize);
	y0 = int((y + viewArea.y1*scale - 0.5f*imageSize) / imageSize);
}

//
// Render
//

void Map::Render(hgeRect &viewArea, bool drawAreaLines)
{
	TileSet &set = GetTileSet(tileSet);

	const float scale = ScreenWidth() / (viewArea.x2 - viewArea.x1);
	const float imageSize = set.imageSize * scale;

	const float x0 = -viewArea.x1*scale;
	const float y0 = -viewArea.y1*scale;

	int i0, i1, j0, j1;
	CalculatePoint(viewArea, -imageSize, -imageSize, j0, i0);
	CalculatePoint(viewArea, ScreenWidth()+imageSize, ScreenHeight()+imageSize, j1, i1);

	//GetLargeFont()->SetColor(0xFFFFFFFF);
	//GetLargeFont()->printf(5, ScreenHeight-60, HGETEXT_LEFT, "(%d, %d) (%d, %d)", i0, j0, i1, j1);

	if(i0 < 0) i0 = 0;
	if(j0 < 0) j0 = 0;
	if(i1 > tHeight) i1 = tHeight;
	if(j1 > tWidth) j1 = tWidth;

	float texSize = 1.0f / set.setSize;

	for(int i = i0; i < i1; i++)
	for(int j = j0; j < j1; j++)
	{
		int t = GetTerrain( i, j );
		if(t == -1) continue;

		tile.v[0].ty = t * texSize;
		tile.v[1].ty = t * texSize;
		tile.v[2].ty = (t + 1) * texSize;
		tile.v[3].ty = (t + 1) * texSize;

		tile.v[0].x = x0 + j * imageSize;
		tile.v[0].y = y0 + i * imageSize;

		tile.v[1].x = x0 + (j +1) * imageSize;
		tile.v[1].y = y0 + i * imageSize;

		tile.v[2].x = x0 + (j + 1) * imageSize;
		tile.v[2].y = y0 + (i + 1) * imageSize;

		tile.v[3].x = x0 + j * imageSize;
		tile.v[3].y = y0 + (i + 1) * imageSize;

		hge->Gfx_RenderQuad(&tile);
	}

	if(drawAreaLines)
		for(int i = i0; i < i1+1; i++)
		for(int j = j0; j < j1+1; j++)
		{
			hge->Gfx_RenderLine(x0, y0 + i * imageSize, x0 + tWidth * imageSize, y0 + i * imageSize, 0xFF00FFFF);
			hge->Gfx_RenderLine(x0 + j * imageSize, y0, x0 + j * imageSize, y0 + tHeight * imageSize, 0xFF00FFFF);
		}
}
